//---------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="XboxAnalogControl.cs" company="DarkWynter Studios">
//     Copyright (C)2007 DarkWynter Studios.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------

namespace DarkWynter.Engine.Controllers
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Input;
    using System.Diagnostics;

    //using DarkWynter.Engine.ObjectLib;
    //using DarkWynter.Engine.Menus;
    //using Globals;
    #endregion

    /// <summary>
    /// Xbox analog event class for mapping an analog button/motion to an event
    /// </summary>
    public class XboxAnalogControl
    {
        private float GAMEPAD_ROTATION_SCALE_Y = 0.03f;
        private float GAMEPAD_ROTATION_SCALE_X = 0.03f;

         // Time delay between key presses to avoid double input
        private int KEY_TIMER_MAX_MILLI = 100;
        private Stopwatch controlTimer = new Stopwatch();

        /// <summary>
        /// On stick delegate type
        /// </summary>
        /// <param name="args">Controller vector2 event arguments</param>
        public delegate void OnStickHandler(ControllerVec2EventArgs args);
        private event OnStickHandler stick;

        /// <summary>
        /// On trigger delegate type
        /// </summary>
        /// <param name="args">Controller float event arguments</param>
        public delegate void OnTriggerHandler(ControllerFloatEventArgs args);
        private event OnTriggerHandler trigger;

        /// <summary>
        /// Type of control for this event
        /// </summary>
        public XboxAnalogControlType controlType;

        /// <summary>
        /// Stick constructor
        /// </summary>
        /// <param name="type">Stick control type</param>
        /// <param name="onStickHandler">Stick handler</param>
        /// <param name="timerValue">Time delay between multiple invocations</param>
        public XboxAnalogControl(XboxAnalogControlType type, OnStickHandler onStickHandler, int timerValue)
        {
            controlType = type;
            controlTimer.Start();
            KEY_TIMER_MAX_MILLI = timerValue;

            stick += new OnStickHandler(onStickHandler);
        }
        /// <summary>
        /// Trigger constructor
        /// </summary>
        /// <param name="type">Trigger control type</param>
        /// <param name="onTriggerHandler">Trigger handler</param>
        /// <param name="timerValue">Time delay between multiple invocations</param>
        public XboxAnalogControl(XboxAnalogControlType type, OnTriggerHandler onTriggerHandler, int timerValue)
        {
            controlType = type;
            controlTimer.Start();
            KEY_TIMER_MAX_MILLI = timerValue;

            trigger += new OnTriggerHandler(onTriggerHandler);
        }

        /// <summary>
        /// Update Method
        /// </summary>
        /// <param name="gamePadState">Updated game pad state</param>
        /// <param name="objectLibrary">Object Library</param>
        /// <param name="menuSystem">Menu System</param>
        public void Update(GamePadState gamePadState, ref List<object> argObjects)
        {
            // Check double-input timer
            if (controlTimer.ElapsedMilliseconds > KEY_TIMER_MAX_MILLI)
            {
                // Reset timer
                controlTimer.Reset();
                controlTimer.Start();
                
                #region JoySticks
                if (controlType == XboxAnalogControlType.LEFT_STICK)
                {
                    if (stick != null)
                    {
                        // Store sign (+/-) of input
                        int xSign = (int)(gamePadState.ThumbSticks.Right.X / Math.Abs(gamePadState.ThumbSticks.Right.X));
                        int ySign = (int)(gamePadState.ThumbSticks.Right.Y / Math.Abs(gamePadState.ThumbSticks.Right.Y));

                        // Calc motion by squaring input (x^2 input curve)
                        Vector2 stickRotation = new Vector2(
                            GAMEPAD_ROTATION_SCALE_X * (gamePadState.ThumbSticks.Right.X * gamePadState.ThumbSticks.Right.X) * xSign,
                            GAMEPAD_ROTATION_SCALE_Y * (gamePadState.ThumbSticks.Right.Y * gamePadState.ThumbSticks.Right.Y) * ySign);

                        stick(new ControllerVec2EventArgs(stickRotation, ref argObjects));
                    }
                }
                else if (controlType == XboxAnalogControlType.RIGHT_STICK)
                {
                    if (stick != null)
                    {
                        // Store sign (+/-) of input
                        int xSign = (int)(gamePadState.ThumbSticks.Right.X / Math.Abs(gamePadState.ThumbSticks.Right.X));
                        int ySign = (int)(gamePadState.ThumbSticks.Right.Y / Math.Abs(gamePadState.ThumbSticks.Right.Y));

                        // Calc motion by squaring input (x^2 input curve)
                        Vector2 stickRotation = new Vector2(
                            GAMEPAD_ROTATION_SCALE_X * (gamePadState.ThumbSticks.Right.X * gamePadState.ThumbSticks.Right.X) * xSign,
                            GAMEPAD_ROTATION_SCALE_Y * (gamePadState.ThumbSticks.Right.Y * gamePadState.ThumbSticks.Right.Y) * ySign);

                        stick(new ControllerVec2EventArgs(stickRotation, ref argObjects));
                    }
                }
                #endregion
                
                #region Triggers
                else if (controlType == XboxAnalogControlType.LEFT_TRIGGER)
                {
                    if (stick != null)
                    {
                        trigger(new ControllerFloatEventArgs(gamePadState.Triggers.Left, ref argObjects));
                    }
                }
                else if (controlType == XboxAnalogControlType.RIGHT_TRIGGER)
                {
                    if (stick != null)
                    {
                        trigger(new ControllerFloatEventArgs(gamePadState.Triggers.Right, ref argObjects));
                    }
                }
                #endregion
            }
        }
    }  
}
